#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <sstream>
#include <fstream>

const static std::string sep = "\r\n";
const static std::string header_sep = ": ";
const static std::string prefix_path = "wwwroot";  // web根目录
const static std::string home_page = "index.html"; // 首页
const static std::string httpservervision = "HTTP/1.0";
const static std::string spacesep = " ";
const static std::string suffixsep = ".";

class HttpRequest
{
private:
    //  basic property
    std::string _line;
    std::vector<std::string> _headers;
    std::string _blank;
    std::string _content;

    // specific request
    std::string _method;
    std::string _url;  // 用户访问的资源，不是完整的路径 --- 用户给的
    std::string _path; // 用户访问的资源，完整的路径 --- 底层拼接的完整的
    std::string _vision;
    std::string _suffix; // 文件后缀
    std::unordered_map<std::string, std::string> _header;

private:
    // 获取一行
    std::string getLine(std::string &req)
    {
        int pos = req.find(sep);
        if (pos == std::string::npos)
            return std::string();

        std::string t = req.substr(0, pos);
        req.erase(0, pos + sep.size());
        if (t.empty())
            return sep;
        return t;
    }
    // 从请求行中获得属性
    void parseReqLine(const std::string &line)
    {
        std::stringstream ss(line);

        ss >> _method >> _url >> _vision;

        _path += _url;

        // wwwroot/index.html
        // wwwroot/image/1.png
        auto pos = _path.rfind(suffixsep);
        if (pos != std::string::npos)
        {
            _suffix = _path.substr(pos);
        }
        else
        {
            _suffix = ".default";
        }
    }
    // 分离报头
    void divideHeader(std::vector<std::string> &headers)
    {
        for (auto &header : headers)
        {
            int pos = header.find(header_sep);
            if (pos == std::string::npos)
                continue;
            std::string key = header.substr(0, pos);
            std::string value = header.substr(pos + header_sep.size());
            if (key.empty() || value.empty())
                continue;

            _header.insert(make_pair(key, value));
        }
    }

public:
    HttpRequest()
        : _path(prefix_path)
    {
    }
    // 反序列化
    void deSerialize(std::string req)
    {
        // 获取请求行
        _line = getLine(req);
        std::string t;
        while ((t = getLine(req)) != sep)
        {
            _headers.push_back(t);
        }
        _blank = sep;
        _content = req;

        // 分离请求行
        parseReqLine(_line);
        // 分离报头
        divideHeader(_headers);
    }
    std::string URL()
    {
        LOG(DEBUG, "client want url: %s\n", _url.c_str());
        return _url;
    }
    std::string PATH()
    {
        if (_path[_path.size() - 1] == '/')
        {
            _path += home_page;
        }
        LOG(DEBUG, "client want path: %s\n", _path.c_str());
        return _path;
    }
    std::string CONTENT()
    {
        return _content;
    }
    std::string SUFFIX()
    {
        return _suffix;
    }
    void print()
    {
        std::cout << "###" << _line << std::endl;
        for (auto &header : _headers)
        {
            std::cout << "@@@" << header << std::endl;
        }
        std::cout << _blank;
        std::cout << _content << std::endl;

        std::cout << _method << " " << _url << " " << _vision << std::endl;
        for (auto &[x, y] : _header)
        {
            std::cout << x << " -> " << y << std::endl;
        }
    }
    ~HttpRequest() {}
};
class HttpRespond
{
private:
    // 基本属性
    std::string _line;
    std::vector<std::string> _headers;
    std::string _blank;
    std::string _content;

    // 具体属性
    std::string _vision;
    int _statcode;
    std::string _desc;
    std::unordered_map<std::string, std::string> _headers_kv;

public:
    HttpRespond()
        : _vision(httpservervision), _blank(sep)
    {
    }
    void AddCode(int code, const std::string &desc)
    {
        _statcode = code;
        _desc = desc;
    }
    void AddHeader(const std::string &k, const std::string &v)
    {
        _headers_kv[k] = v;
    }
    void AddBodyText(const std::string &body_text)
    {
        _content = body_text;
    }
    std::string Serialize()
    {
        // 构建行
        _line = _vision + spacesep + std::to_string(_statcode) + spacesep + _desc = spacesep;
        // 应答报头
        for (auto &header : _headers_kv)
        {
            std::string line = header.first + header_sep + header.second + sep;
            _headers.push_back(line);
        }
        // 空行和正文

        // 序列化
        std::string respondstr = _line;
        for (auto &line : _headers)
        {
            respondstr += line;
        }
        respondstr += _blank;
        respondstr += _content;

        return respondstr;
    }
    ~HttpRespond() {}
};

class HttpServer
{
private:
    std::unordered_map<std::string, std::string> _mime_type;

private:
    std::string getFileContent(std::string path)
    {
        std::ifstream in(path, std::ios::binary);
        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);
        std::string content;
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);
        in.close();
        return content;
    }

public:
    HttpServer()
    {
        _mime_type.insert(std::make_pair(".html", "text/html"));
        _mime_type.insert(std::make_pair(".jpg", "image/jpeg"));
        _mime_type.insert(std::make_pair(".png", "image/png"));
        _mime_type.insert(std::make_pair(".default", "text/html"));
    }
    std::string handlerHttpRequest(const std::string &req)
    {
#ifdef TEST
        std::cout << "----------------------------------" << std::endl;
        std::cout << req << std::endl;

        std::string responsestr = "HTTP/1.1 200 OK\r\n";
        responsestr += "Content-Type: text/html\r\n";
        responsestr += "\r\n";
        responsestr += "<html><h1>hello Linux, hello bite!</h1></html>";
        return responsestr;
#else
        HttpRequest hrequest;
        hrequest.deSerialize(req);
        hrequest.print();

        HttpRespond hrespond;
        std::string content = getFileContent(hrequest.PATH());
        if (content.empty())
        {
            // 404
        }
        else
        {
            hrespond.AddCode(200, "success");
            hrespond.AddHeader("Content-Length", std::to_string(content.size()));
            hrespond.AddHeader("Content-Type", _mime_type[hrequest.SUFFIX()]);
            hrespond.AddHeader("Set-Cookie", "username=zhangsan");
            hrespond.AddBodyText(content);
        }

        return hrespond.Serialize();
#endif
    }
    ~HttpServer() {}
};